package com.cn.utils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

@Log4j2
public class CTRUtil {
    public static void main(String[] args) throws Exception {
        //定义密钥
        String key = "xuOs0lv9Yqjj1BwE";
        //定义加密的偏移量
        String iv = "1234567890123456";
        String name = "测试,你好,解密成功";
        String enResult = encryptCRT(name.getBytes(),key,iv);
        System.out.println("加密后：=======" + enResult);
        String deResult = decryptCRT(enResult, key,iv);
        System.out.println("解密后：=======" + deResult);
    }

    /**
     * AES CRT加密 填充为PKCS5
     *
     * @param content 要加密的内容
     * @param key     加密文件的秘钥
     * @param iv      加密的偏移量
     * @return 输出Hex十六进制再次加密的结果
     **/
    public static String encryptCRT(byte[] content, String key, String iv) {
        String encodeStr = "";
        try {
            //产生密钥
            byte[] keyBytes = key.getBytes();
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
            //构建Cipher对象，需要传入一个字符串，格式必须为"algorithm/mode/padding"或者"algorithm/",意为"算法/加密模式/填充方式"
            Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
            //初始化Cipher对象
            byte[] ivBytes = iv.getBytes();
            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            //加密数据
            byte[] resultBytes = cipher.doFinal(content);
            //结果用Hex十六进制转码
            encodeStr = new String(Hex.encodeHex(resultBytes));
            return encodeStr;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return encodeStr;
    }

    /**
     * AES CTR 解密
     * <p>
     * 填充为PKCS5
     *
     * @param encode 加密过后的文件
     * @param iv     偏移量
     * @param key    秘钥文件
     */

    public static String decryptCRT(String encode,  String key, String iv) {
        String decoded = "";
        try {
            byte[] bytes = Hex.decodeHex(encode);
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
            Key keys = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, keys, ivSpec);
            byte[] ret = cipher.doFinal(bytes);
            decoded = new String(ret);
            return decoded.trim();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (DecoderException e) {
            e.printStackTrace();
        }
        return decoded;
    }

    /**
     * 获取AES编码规则
     *
     * @return
     */
    public static String genEncodeRule() {
        StringBuilder chars = new StringBuilder("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < 16; i++) {
            int num = Integer.parseInt(String.valueOf(Math.round(Math.floor(Math.random() * chars.length()))));
            result.append(chars.charAt(num));
        }
        return result.toString();
    }
}
